package com.funi;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.funi.bo.BranchBo;
import com.funi.bo.CommitBo;
import com.funi.bo.ProjectBo;
import com.funi.bo.UserBo;
import com.funi.consts.Constants;
import com.funi.vo.DeveloperContributedCodeLineStatResult;
import lombok.extern.slf4j.Slf4j;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.models.*;
import org.junit.Test;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.stream.Collectors;

/**********************************************************************
 * &lt;p&gt;文件名：Test4.java &lt;/p&gt;
 * &lt;p&gt;文件描述：(描述该文件做什么) https://www.bookstack.cn/read/gitlab-doc-zh/docs-301.md
 * 原工具代码逻辑处理耦合太重，过于臃肿。已经重构，请移步{@link FuniGitLabCodeCommitStats}
 * @project_name：code_total
 * @author zengshunyao
 * @create 2025/5/28 18:34
 * @history
 * @department：政务事业部
 * Copyright ChengDu Funi Cloud Code Technology Development CO.,LTD 2014 
 *                    All Rights Reserved.
 */
@Slf4j
@Deprecated
public class FuniGitLabCodeCommitStatsOld {

    /**
     * Count the number of lines of code contributed by the author
     * 统计人员某段时间的代码变更(新增或删除)总行数
     * 原耦合太重，过于臃肿。已经重构，请移步{@link FuniGitLabCodeCommitStats}
     *
     * @throws Exception
     */
    @Test
    public void authorContributedCodeLineCount() throws Exception {
        System.err.println("运行开始时间:" + DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
        final long begin = System.currentTimeMillis();
        //存储统计结果
        final List<DeveloperContributedCodeLineStatResult> resultList = new ArrayList<>();
        //启用日志,启用对GitLab服务器API的请求和响应的日志记录
        Constants.GitLabAPI.enableRequestResponseLogging(Level.ALL);

        //所有人员列表,烂的不要用
        //List<User> userList = gitLabAPI.getUserApi().getUsers();
        //log.info("人员列表:{}", JSON.toJSONString(userList));

        //获取GitLab中的所有开发人员信息(组、项目下)
        final List<User> allActiveUserList = this.getAllDevelopers();

        log.info("==========================================>1.研发人员列表<==========================================");
        log.info("所有活跃研发人员列表:{}", JSON.toJSONString(allActiveUserList));

        //筛选出 成都研发部 的开发人员
        final List<User> cdGroupActiveUserList = allActiveUserList.stream().filter(u ->
                Constants.CD_GROUP_MEMBER_USERNAME_LIST.stream()
                        .anyMatch(
                                p ->
                                        Objects.equals(p.getName(), u.getName())
                                                || Objects.equals(p.getName(), u.getUsername())
                                                //兼顾拼音，解决刘毅和郑礼珂账号问题
                                                || Objects.equals(p.getNamePinYi(), u.getName())
                                                || Objects.equals(p.getNamePinYi(), u.getUsername())
                                                //邮箱匹配
                                                || Objects.equals(p.getEmail(), u.getEmail())

                        )).sorted(Comparator.comparing(User::getId)).collect(Collectors.toList());

        //打印
        //log.info("成都研发部中活跃的人员列表:{}", JSON.toJSONString(cdGroupActiveUserList.stream().map(AbstractUser::getName).collect(Collectors.toList())));


        log.info("==========================================>2.获取指定时间范围内有代码提交活动的项目数<==========================================");
        //所有工程项目清单
        final List<Project> projectList = Constants.GitLabAPI.getProjectApi().getProjects();
        //log.info("查询项目列表:{}", JSON.toJSONString(projectList));
        log.info("查询项目列表数量:{}", projectList.size());
        final List<ProjectBo> projectBoList = this.obtainProjectAndCommitWithinTimeFrame(projectList, Constants.START_TIME, Constants.END_TIME);
        //log.info("公司所有的项目列表:{}", JSON.toJSONString(projectBoList.stream().map(e -> e.getProjectId() + "-" + e.getProject().getName()).collect(Collectors.toList())));
        log.info("查询指定时间范围内有代码提交活动的项目数量:{}", projectBoList.size());
        //存储所有提交记录
        final List<CommitBo> allCommitListWithProject = new ArrayList<CommitBo>();
        //遍历所有项目，寻找代码提交记录
        for (final ProjectBo p : projectBoList) {
            //记录提交记录到临时容器 中
            allCommitListWithProject.addAll(p.getAllBranchCommitListWithProject());
        }

        log.info("==========================================>3.逐步统计各个活跃的研发人员代码提交行数<==========================================");
        for (final User activeUser : cdGroupActiveUserList) {
            //新增、删除、变更
            Integer addCode = 0;
            Integer delCode = 0;
            Integer totalCode = 0;

            //用户id，姓名，账号，状态，邮箱
            final Integer userId = activeUser.getId();
            final String name = activeUser.getName();
            final String userName = activeUser.getUsername();
            final String state = activeUser.getState();
            String email = activeUser.getEmail();

            //检查用户信息,不符合要求的用户如 blocked 可进行跳过
            if (checkUserInfo(name, state)) {
                continue;
            }

            //部门员工与git成员对应匹配
            UserBo curUserBo = null;
            for (UserBo userBo : Constants.CD_GROUP_MEMBER_USERNAME_LIST) {
                //多种方式匹配。兼容git预留账号、邮箱信息不匹配的问题
                if (Objects.equals(userBo.getName(), activeUser.getName())
                        || Objects.equals(userBo.getNamePinYi(), activeUser.getName())
                        || Objects.equals(userBo.getName(), activeUser.getUsername())
                        || Objects.equals(userBo.getNamePinYi(), activeUser.getUsername())
                        || Objects.equals(userBo.getEmail(), activeUser.getEmail())
                ) {
                    curUserBo = userBo;
                }
            }
            if (Objects.isNull(curUserBo)) {
                log.error("异常：未找到开发者{}", userName);
                continue;
            }

            //遍历所有项目，寻找该开发人员的代码提交记录
            for (final ProjectBo projectBo : projectBoList) {
                final Project project = projectBo.getProject();
                final Integer projectId = projectBo.getProjectId();
                //新增、删除、变更
                Integer projectAddCode = 0;
                Integer projectDelCode = 0;
                Integer projectTotalCode = 0;
                //记录当前项目的分支
                final List<BranchBo> curUserBoBranchList = new ArrayList<>();

                for (final BranchBo branchBo : projectBo.getBranchBoList()) {
                    final String branchName = branchBo.getBranchName();

                    //新增、删除、变更
                    Integer projectBranchAddCode = 0;
                    Integer projectBranchDelCode = 0;
                    Integer projectBranchTotalCode = 0;

                    //记录开发者在本项目的当前分支的提交记录
                    final List<CommitBo> curUserBoBranchCommitList = new ArrayList<>();

                    //筛选本开发者的提交记录
                    for (CommitBo commitBo : branchBo.getCommitBoList()) {
                        //因commit信息中没有用户的memberId信息,每个人提交信息可能有些缺失,故多个条件进行灵活匹配 判断
                        final Commit commit = commitBo.getCommit();
                        if (
                                Objects.equals(userName, commit.getAuthorName())//用户名中文
                                        || Objects.equals(userName, commit.getAuthorEmail())
                                        || Objects.equals(userName, commit.getCommitterName())
                                        || Objects.equals(userName, commit.getCommitterEmail())
                                        //用户名拼音
                                        //兼顾刘毅、郑礼珂 问题账号
                                        || Objects.equals(curUserBo.getName(), commit.getAuthorName())
                                        || Objects.equals(curUserBo.getName(), commit.getCommitterName())
                                        || Objects.equals(curUserBo.getNamePinYi(), commit.getAuthorName())
                                        || Objects.equals(curUserBo.getNamePinYi(), commit.getCommitterName())
                                        || Objects.equals(curUserBo.getEmail(), commit.getCommitterEmail())
                        ) {
                            final Commit c = Constants.GitLabAPI.getCommitsApi().getCommit(project.getId(), commit.getShortId());

                            //添加代码行数
                            projectBranchAddCode += c.getStats().getAdditions();
                            //删除代码行数
                            projectBranchDelCode += c.getStats().getDeletions();
                            //累计修改行数
                            projectBranchTotalCode += c.getStats().getTotal();

                            //记录提交邮箱
                            if (Objects.isNull(email) && Objects.nonNull(c.getCommitterEmail())) {
                                //如果开发者账号未预留邮箱且代码提交中的邮箱存在,则用代码提交中的邮箱兜底
                                email = c.getCommitterEmail();
                            }
                            if (projectBranchTotalCode > 0) {
                                //有变化
                                curUserBoBranchCommitList.add(commitBo);
                            }
                        }
                    }
                    log.info("开始时间：{},结束时间：{}, projectId：{},branchName：{},userId：{}, 姓名：{}, email：{}, 添加代码行数:{}, 删除代码行数:{}, 累计变更行数：{}"
                            , Constants.START_TIME, Constants.END_TIME, projectId, branchName, userId, name, email, projectBranchAddCode, projectBranchDelCode, projectBranchTotalCode);
                    projectAddCode += projectBranchAddCode;
                    //删除代码行数
                    projectDelCode += projectBranchDelCode;
                    //累计修改行数
                    projectTotalCode += projectBranchTotalCode;

                    if (projectBranchTotalCode > 0) {
                        //记录当前开发者提交分支
                        final BranchBo curUserPoBranchBo = BranchBo.builder()
                                .branchName(branchName)
                                .commitBoList(curUserBoBranchCommitList)
                                .since(Constants.START_TIME)
                                .until(Constants.END_TIME)
                                .build();
                        curUserBoBranchList.add(curUserPoBranchBo);
                    }
                }
                log.info("开始时间：{},结束时间：{},  projectId：{},userId：{}, 姓名：{}, email：{}, 添加代码行数:{}, 删除代码行数:{}, 累计变更行数：{}"
                        , Constants.START_TIME, Constants.END_TIME, projectId, userId, name, email, projectAddCode, projectDelCode, projectTotalCode);

                addCode += projectAddCode;
                //删除代码行数
                delCode += projectDelCode;
                //累计修改行数
                totalCode += projectTotalCode;
                if (projectTotalCode > 0) {
                    curUserBo.getInvolvedProjectBoList().add(
                            new ProjectBo(projectBo.getProjectId(),
                                    projectBo.getProject(),
                                    curUserBoBranchList,
                                    projectBo.getSince(),
                                    projectBo.getUntil(),
                                    curUserBoBranchList.stream()
                                            .filter(b -> b != null && b.getCommitBoList() != null && b.getCommitBoList().size() > 0)
                                            .flatMap(b -> b.getCommitBoList().stream())
                                            .distinct()
                                            .collect(Collectors.toList())
                            )

                    );
                }
            }
            log.info("开始时间：{},结束时间：{}, userId：{}, 姓名：{}, email：{}, 添加代码行数:{}, 删除代码行数:{}, 累计变更行数：{}"
                    , Constants.START_TIME, Constants.END_TIME, userId, name, email, addCode, delCode, totalCode);
            //添加到结果集
            resultList.add(
                    DeveloperContributedCodeLineStatResult.builder()
                            .since(Constants.START_TIME_STR)
                            .until(Constants.END_TIME_STR)
                            .userBo(curUserBo)
                            .id(userId)
                            .name(name)
                            .email(email)
                            .addCode(addCode)
                            .delCode(delCode)
                            .totalCode(totalCode)
                            .involvedProjectBoList(curUserBo.getInvolvedProjectBoList())
                            .build()
            );
        }

        log.info("==========================================>代码提交量排行榜<==========================================");
        //倒排
        resultList.stream()
                .sorted((a, b) -> b.getTotalCode().compareTo(a.getTotalCode()))
                .collect(Collectors.toList())
                .forEach(System.err::println);

        System.err.println("运行结束时间:" + DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
        final long costTime = System.currentTimeMillis() - begin;
        System.err.println("耗时:" + TimeUnit.MILLISECONDS.toSeconds(costTime) + "秒");
    }

    /**
     * 获取 所有 developer 人员信息
     *
     * @return
     * @throws Exception
     */
    private List<User> getAllDevelopers() throws Exception {
        //存储所有的参与成员
        final List<User> userList = new ArrayList<User>();
        //存储所有的工程项目
        final List<Project> projectList = new ArrayList<>();

        //获取所有组
        final List<Group> groupList = Constants.GitLabAPI.getGroupApi().getGroups();
        //所有组路径下的人员和项目信息
        {
            log.info("==========================================>组清单<==========================================");
            for (final Group g : groupList) {
                log.info("组名称：{},组全名称：{}, 组描述：{},组路径：{}", g.getName(), g.getFullName(), g.getDescription(), g.getFullPath());
                //记录当前组下所有工程项目项目
                projectList.addAll(Constants.GitLabAPI.getGroupApi().getProjects(g.getId()));
                //记录当前组下所有人员
                final List<Member> membersWithinGroup = Constants.GitLabAPI.getGroupApi().getMembers(g.getId());
                for (final Member m : membersWithinGroup) {
                    if (!checkMemberExist(userList, m)) {
                        //跳过已添加过的用户
                        final User user = Constants.GitLabAPI.getUserApi().getUser(m.getId());
                        userList.add(user);
                    }
                }
            }
        }

        //获取所有Project下的人员信息
        log.info("==========================================>项目清单<==========================================");
        for (Project project : projectList) {
            //项目code、id、描述、http地址
            final String projectName = project.getPath();
            final Integer projectId = project.getId();
            final String description = project.getDescription();
            final String webUrl = project.getWebUrl();
            log.info("项目名称：{}, 项目Id：{}, 项目描述：{}, 项目WEB地址：{}", projectName, projectId, description, webUrl);
            //获取项目下人员信息
            final List<Member> members = Constants.GitLabAPI.getProjectApi().getMembers(projectId);
            for (final Member m : members) {
                if (!checkMemberExist(userList, m)) {
                    //跳过已添加过的用户
                    final User user = Constants.GitLabAPI.getUserApi().getUser(m.getId());
                    userList.add(user);
                }
            }
        }
        //去重
        return new ArrayList<>(new HashSet<>(userList));
    }

    /**
     * 获取所有分支
     *
     * @param projectId 项目id
     * @return
     */
    private List<String> getBranches(String projectId) {
        // 获取所有分支
        try {
            List<Branch> branches = Constants.GitLabAPI.getRepositoryApi().getBranches(projectId);
            return branches.stream().map(Branch::getName).collect(Collectors.toList());
        } catch (GitLabApiException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 根据项目清单获取项目的代码提交情况
     *
     * @param projectList 项目集合
     * @param startTime   开始时间
     * @param endTime     结束时间
     */
    private List<ProjectBo> obtainProjectAndCommitWithinTimeFrame(final List<Project> projectList, final Date startTime, final Date endTime) throws GitLabApiException {
        final List<ProjectBo> projectBoList = new ArrayList<>();
        //遍历所有项目，寻找该开发人员的代码提交记录
        for (final Project project : projectList) {
            //"master"
            //存储指定项目的所有提交记录
            final List<CommitBo> curProjectCommitListWithProject = new ArrayList<CommitBo>();

            //项目code、id、描述、http地址
            final ProjectBo projectBo = ProjectBo.builder()
                    .projectId(project.getId())
                    .project(project)
                    .since(startTime)
                    .until(endTime)
                    .build();
            {
                //所有分支循环遍历 代码提交记录
                final List<String> branches = this.getBranches(String.valueOf(project.getId()));
                for (final String branchName : branches) {
                    //final List<Commit> curBranchCommitList = gitLabAPI.getCommitsApi().getCommits(project.getId(), branchName, startTime, endTime);
                    final List<Commit> curBranchCommitList = Constants.GitLabAPI.getCommitsApi().getCommits(
                            project.getId(),//以Integer（ID）、String（路径）或project实例的形式对项目进行路径设置
                            branchName,//引用存储库分支或标记的名称，如果没有给出 则默认分支
                            startTime,//因为只有在此日期之后或当天提交的才会被返回
                            endTime,//直到只返回此日期之前或当天的提交
                            null,//项目文件的路径
                            true,//全部从存储库中检索每个提交
                            true,//全部从存储库中检索每个提交 关于每次提交的@param with stats统计数据将添加到响应中
                            true//在看到合并提交时仅跟随第一个父提交
                    );
                    final List<CommitBo> curBranchCommitBoList = curBranchCommitList.stream().map(e -> new CommitBo(e, project.getId(), branchName, startTime, endTime)).collect(Collectors.toList());
                    //添加提交记录到项目
                    projectBo.getBranchBoList().add(new BranchBo(branchName, curBranchCommitBoList, projectBo.getSince(), projectBo.getUntil()));
                    //记录提交记录到临时容器 中
                    curProjectCommitListWithProject.addAll(curBranchCommitBoList);
                }
            }
            //存在分支
            if (projectBo.getBranchBoList().size() > 0) {
                projectBo.getAllBranchCommitListWithProject().addAll(curProjectCommitListWithProject);
            }
            projectBoList.add(projectBo);
        }
        return projectBoList;
    }

    /**
     * 判断人员是否已经存在
     *
     * @param userList
     * @param m
     * @return
     */
    private boolean checkMemberExist(final List<User> userList, final Member m) {
        //for (User user : userList) {
        //    if (user.getId().equals(m.getId())) {
        //        return true;
        //    }
        //}
        //return false;
        return userList.stream().anyMatch(u -> Objects.equals(u.getId(), m.getId()));
    }

    /**
     * 筛选出已经离职或其他人员
     *
     * @param name
     * @param state
     * @return
     */
    private boolean checkUserInfo(String name, String state) {
        return state.equals("blocked") || name.contains("产品部");
    }
}
